<template>
  <div class="storage-config-container">
    <!-- 左侧导航 -->
    <div class="sidebar">
      <div class="sidebar-menu">
        <div class="menu-item" :class="{ active: activeTab === 'storage' }" @click="activeTab = 'storage'">
          <svg class="menu-icon" width="16" height="16" viewBox="0 0 16 16" fill="none">
            <path d="M2 3C2 2.44772 2.44772 2 3 2H13C13.5523 2 14 2.44772 14 3V5C14 5.55228 13.5523 6 13 6H3C2.44772 6 2 5.55228 2 5V3Z" fill="currentColor"/>
            <path d="M2 8C2 7.44772 2.44772 7 3 7H13C13.5523 7 14 7.44772 14 8V10C14 10.5523 13.5523 11 13 11H3C2.44772 11 2 10.5523 2 10V8Z" fill="currentColor"/>
            <path d="M3 12C2.44772 12 2 12.4477 2 13V15C2 15.5523 2.44772 16 3 16H13C13.5523 16 14 15.5523 14 15V13C14 12.4477 13.5523 12 13 12H3Z" fill="currentColor"/>
          </svg>
          存储配置
        </div>
        <div class="menu-item" :class="{ active: activeTab === 'backup' }" @click="activeTab = 'backup'">
          <svg class="menu-icon" width="16" height="16" viewBox="0 0 16 16" fill="none">
            <path d="M8 2L10.5 4.5H13V13H3V4.5H5.5L8 2Z" stroke="currentColor" stroke-width="1.5" fill="none"/>
            <path d="M6 7H10M6 9H10" stroke="currentColor" stroke-width="1.5"/>
          </svg>
          备份与恢复
        </div>
      </div>
    </div>

    <!-- 主要内容区域 -->
    
    <div class="main-content">
      <h2 class="section-title">数据存储配置</h2>
      <!-- 存储配置页面 -->
      <div v-if="activeTab === 'storage'" class="config-content">
        <!-- 存储池配置区域 -->
        <div class="config-section">
          <div class="section-header">
            <h3>存储类型配置</h3>
          </div>
          <div class="form-container">
            <div class="form-grid-two-column">
              <div class="form-column">
                <div class="form-row">
                  <label>结构化数据库：</label>
                  <a-select :value="storageConfig.structuredDb" @change="val => (storageConfig.structuredDb = val)" placeholder="选择数据库类型xxx.xxx">
                    <a-select-option value="mysql">MySQL数据库</a-select-option>
                    <a-select-option value="postgresql">PostgreSQL数据库</a-select-option>
                    <a-select-option value="oracle">Oracle数据库</a-select-option>
                  </a-select>
                </div>
                <div class="form-row">
                  <label>数据库连接地址：</label>
                  <a-input :value="storageConfig.dbAddress" @update:value="val => (storageConfig.dbAddress = val)" placeholder="db.example.com:3306" />
                </div>
                <div class="form-row">
                  <label>数据库名称：</label>
                  <a-input :value="storageConfig.dbName" @update:value="val => (storageConfig.dbName = val)" placeholder="xxxxxxx" />
                </div>
              </div>
              <div class="form-column">
                <div class="form-row">
                  <label>非结构化数据库：</label>
                  <a-select :value="storageConfig.unstructuredDb" @change="val => (storageConfig.unstructuredDb = val)" placeholder="国产分布文件系统xxxx">
                    <a-select-option value="hdfs">HDFS</a-select-option>
                    <a-select-option value="ceph">Ceph</a-select-option>
                    <a-select-option value="glusterfs">GlusterFS</a-select-option>
                  </a-select>
                </div>
                <div class="form-row">
                  <label>存储路径：</label>
                  <a-input :value="storageConfig.storagePath" @update:value="val => (storageConfig.storagePath = val)" placeholder="/data/xxx/xxx" />
                </div>
                <div class="form-row">
                  <label>非结构化数据库：</label>
                  <a-select :value="storageConfig.unstructuredDbType" @change="val => (storageConfig.unstructuredDbType = val)" placeholder="国产非关系型数据库xxxx">
                    <a-select-option value="mongodb">MongoDB</a-select-option>
                    <a-select-option value="cassandra">Cassandra</a-select-option>
                    <a-select-option value="redis">Redis</a-select-option>
                  </a-select>
                </div>
              </div>
            </div>
            <div class="form-actions">
              <a-button type="primary" :loading="savingType" @click="submitStorageTypeConfig">保存配置</a-button>
            </div>
          </div>
        </div>

        <!-- 存储池状态区域 -->
        <div class="config-section">
          <div class="section-header">
            <h3>存储参数配置</h3>
          </div>
          <div class="form-container">
            <div class="form-grid">
              <div class="form-row">
                <label>最大连接数：</label>
                <a-input :value="poolStatus.maxConnections" @update:value="val => (poolStatus.maxConnections = val)" placeholder="100" />
              </div>
              <div class="form-row">
                <label>事务隔离级别：</label>
                <a-select :value="poolStatus.isolationLevel" @change="val => (poolStatus.isolationLevel = val)" placeholder="READ COMMITTED">
                  <a-select-option value="READ COMMITTED">READ COMMITTED</a-select-option>
                  <a-select-option value="READ UNCOMMITTED">READ UNCOMMITTED</a-select-option>
                  <a-select-option value="REPEATABLE READ">REPEATABLE READ</a-select-option>
                  <a-select-option value="SERIALIZABLE">SERIALIZABLE</a-select-option>
                </a-select>
              </div>
              <div class="form-row">
                <label>日志保留时间：</label>
                <a-select :value="poolStatus.logRetention" @change="val => (poolStatus.logRetention = val)" placeholder="保留60天">
                  <a-select-option value="30">保留30天</a-select-option>
                  <a-select-option value="60">保留60天</a-select-option>
                  <a-select-option value="90">保留90天</a-select-option>
                  <a-select-option value="180">保留180天</a-select-option>
                </a-select>
              </div>
            </div>
            <div class="form-actions">
              <a-button type="primary" :loading="savingParam" @click="submitStorageParamConfig">保存配置</a-button>
            </div>
          </div>
        </div>
      </div>

      <!-- 备份与恢复页面 -->
      <div v-if="activeTab === 'backup'" class="config-content">
        <!-- 新建备份策略区域 -->
        <div class="config-section">
          <div class="section-header">
            <h3>新建备份策略</h3>
          </div>
          <div class="form-container">
            <div class="form-grid-two-column">
              <div class="form-column">
                <div class="form-row">
                  <label>策略名称：</label>
                  <a-input :value="backupStrategy.strategyName" @update:value="val => (backupStrategy.strategyName = val)" placeholder="请输入策略名称" />
                </div>
                <div class="form-row">
                  <label>备份类型：</label>
                  <a-select :value="backupStrategy.backupType" @change="val => (backupStrategy.backupType = val)" placeholder="全量备份">
                    <a-select-option value="full">全量备份</a-select-option>
                    <a-select-option value="incremental">增量备份</a-select-option>
                    <a-select-option value="differential">差异备份</a-select-option>
                  </a-select>
                </div>
                <div class="form-row">
                  <label>备份内容：</label>
                  <a-select :value="backupStrategy.backupContent" @change="val => (backupStrategy.backupContent = val)" placeholder="全部数据库">
                    <a-select-option value="all">备份数据库</a-select-option>
                    <a-select-option value="selected">备份数据库表</a-select-option>
                  </a-select>
                </div>
              </div>
              <div class="form-column">
                <div class="form-row">
                  <label>备份频率：</label>
                  <a-select :value="backupStrategy.backupFrequency" @change="val => (backupStrategy.backupFrequency = val)" placeholder="每30天">
                    <a-select-option value="daily">每天</a-select-option>
                    <a-select-option value="weekly">每周</a-select-option>
                    <a-select-option value="monthly">每30天</a-select-option>
                  </a-select>
                </div>
                <div class="form-row">
                  <label>备份时间：</label>
                  <a-input :value="backupStrategy.backupTime" @update:value="val => (backupStrategy.backupTime = val)" placeholder="00:00" />
                </div>
                <div class="form-row">
                  <label>备份保留时间：</label>
                  <a-select :value="backupStrategy.retentionTime" @change="val => (backupStrategy.retentionTime = val)" placeholder="60天">
                    <a-select-option value="30">30天</a-select-option>
                    <a-select-option value="60">60天</a-select-option>
                    <a-select-option value="90">90天</a-select-option>
                    <a-select-option value="180">180天</a-select-option>
                  </a-select>
                </div>
              </div>
            </div>
            <div class="form-actions">
              <a-button
                type="primary"
                :loading="creating"
                @click="submitBackupStrategy"
              >
                +新建策略
              </a-button>
            </div>
          </div>
        </div>

        <!-- 已有备份策略区域 -->
        <div class="config-section">
          <div class="section-header">
            <h3>已有备份策略</h3>
          </div>
          <div class="backup-cards" v-if="strategyList.length">
            <div class="backup-card" v-for="item in strategyList" :key="item.id">
              <div class="card-header">
                <span class="card-title">{{ item.strategyName }}</span>
                <span class="card-status" :class="item.status === 0 ? 'active' : 'inactive'">{{ formatStatus(item.status) }}</span>
              </div>
              <div class="card-content">
                <div class="card-info">
                  <div class="info-row">
                    <span class="info-label">备份内容：</span>
                    <span class="info-value">{{ formatContent(item.backupContent) }}</span>
                  </div>
                  <div class="info-row">
                    <span class="info-label">备份频率：</span>
                    <span class="info-value">{{ formatFrequency(item.backupFrequency, item.backupTime) }}</span>
                  </div>
                  <div class="info-row">
                    <span class="info-label">最后备份：</span>
                    <span class="info-value">{{ lastBackupMap[item.id] || '-' }}</span>
                  </div>
                </div>
              </div>
              <div class="card-actions">
                <a-button size="small" type="primary" :loading="executingIds.includes(item.id)" @click="openExecuteDialog(item.id)">立即执行</a-button>
                <a-button
                  size="small"
                  :danger="item.status === 0"
                  :loading="togglingIds.includes(item.id)"
                  @click="toggleStrategyStatus(item)"
                  style="margin-left: 8px;"
                >{{ item.status === 0 ? '停用' : '启用' }}</a-button>
                <a-popconfirm
                  title="确定删除该策略吗？此操作不可恢复"
                  ok-text="删除"
                  cancel-text="取消"
                  @confirm="deleteStrategy(item)"
                >
                  <a-button size="small" danger :loading="deletingIds.includes(item.id)" style="margin-left: 8px;">删除</a-button>
                </a-popconfirm>
              </div>
            </div>
          </div>
          <div v-else class="form-container" style="padding-top: 12px;">
            <span style="color:#9ca3af">暂无备份策略，请先在上方创建策略</span>
          </div>
        </div>

        <!-- 数据恢复区域 -->
        <div class="config-section">
          <div class="section-header">
            <h3>数据恢复</h3>
          </div>
          <div class="form-container">
            <div class="form-grid">
              <div class="form-row">
                <label>选择备份文件：</label>
                <a-select
                  v-model="dataRestore.backupFile"
                  :loading="backupFilesLoading"
                  :allowClear="true"
                  show-search
                  placeholder="请选择备份文件"
                  @dropdownVisibleChange="open => open && fetchBackupFiles()"
                  @change="handleBackupFileChange"
                >
                  <a-select-option v-for="f in backupFileOptions" :key="f" :value="f">{{ f }}</a-select-option>
                </a-select>
              </div>
              <div class="form-row full-width">
                <label>备份类型：</label>
                <span style="color:#9ca3af">{{ isTableBackup ? '表级恢复' : '库级恢复' }}</span>
              </div>
              <div class="form-row">
                <label>文件名：</label>
                <span style="color:#9ca3af">{{ backupInfo?.filename || '-' }}</span>
              </div>
              <div class="form-row">
                <label>数据库：</label>
                <span style="color:#9ca3af">{{ backupInfo?.databaseName || '-' }}</span>
              </div>
              <div class="form-row">
                <label>IP/端口：</label>
                <span style="color:#9ca3af">{{ backupInfo?.ip || '-' }}{{ backupInfo?.databasePort ? ':' + backupInfo.databasePort : '' }}</span>
              </div>
              <div class="form-row">
                <label>文件路径：</label>
                <span style="color:#9ca3af">{{ backupInfo?.filePath || '-' }}</span>
              </div>
              <div class="form-row" v-if="backupInfo?.tables">
                <label>表：</label>
                <span style="color:#9ca3af">{{ backupInfo.tables }}</span>
              </div>
              <div class="form-row">
                <label>更新时间：</label>
                <span style="color:#9ca3af">{{ backupInfo?.updateTime || '-' }}</span>
              </div>
              <div class="form-row">
                <label>创建人：</label>
                <span style="color:#9ca3af">{{ backupInfo?.createBy || '-' }}</span>
              </div>
            </div>
            <div class="form-actions">
              <a-button type="primary" :loading="restoring || backupInfoLoading" :disabled="!dataRestore.backupFile" @click="handleStartRestoreClick">开始恢复</a-button>
            </div>
          </div>
        </div>
      </div>
      <!-- 立即执行参数收集弹窗 -->
      <a-modal
        :open="executeDialogVisible"
        @update:open="val => (executeDialogVisible = val)"
        class="light-modal"
        rootClassName="light-modal"
        title="执行参数设置"
        :maskClosable="false"
        :width="760"
        wrapClassName="light-modal"
        okText="确认"
        cancelText="取消"
        :confirmLoading="executeSubmitting"
        @ok="confirmExecute"
        @cancel="() => (executeDialogVisible = false)"
      >
        <div class="form-container execute-modal">
          <div class="form-grid">
            <div class="form-row">
              <label>数据库IP：</label>
              <a-input :value="executeForm.ip" @update:value="val => (executeForm.ip = val)" placeholder="127.0.0.1" />
            </div>
            <div class="form-row">
              <label>数据库端口：</label>
              <a-input :value="executeForm.databasePort" @update:value="val => (executeForm.databasePort = val)" placeholder="5236" />
            </div>
            <div class="form-row">
              <label>数据库密码：</label>
              <a-input-password :value="executeForm.password" @update:value="val => (executeForm.password = val)" placeholder="sYSDBA123" />
            </div>
            <div class="form-row">
              <label>数据库名称：</label>
              <a-input :value="executeForm.databaseName" @update:value="val => (executeForm.databaseName = val)" placeholder="SYSDBA" />
            </div>
            <div class="form-row">
              <label>备份文件路径：</label>
              <a-input :value="executeForm.filePath" @update:value="val => (executeForm.filePath = val)" placeholder="E:/shixiwork/地面站/backup" />
            </div>
            <div class="form-row">
              <label>数据库bin路径：</label>
              <a-input :value="executeForm.binPath" @update:value="val => (executeForm.binPath = val)" placeholder="D://dameng/DM/bin" />
            </div>
          </div>
          <div class="tip-row">请核对数据库连接与文件路径，确保有读写权限。</div>
        </div>
      </a-modal>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, watch, computed } from 'vue'
import { message } from 'ant-design-vue'
import { backupApi } from '@/api/backup'
import { storageApi } from '@/api/storage'

const activeTab = ref('storage')

// 存储池配置
const storageConfig = ref({
  structuredDb: '',
  dbAddress: '',
  dbName: '',
  unstructuredDb: '',
  storagePath: '',
  unstructuredDbType: ''
})

// 存储池状态
const poolStatus = ref({
  maxConnections: '',
  isolationLevel: '',
  logRetention: ''
})

// 新建备份策略配置（设置合理的默认值，避免用户未选择导致拦截）
const backupStrategy = ref({
  strategyName: '',
  backupType: 'full',
  backupContent: 'all',
  backupFrequency: 'monthly',
  backupTime: '00:00',
  retentionTime: '60'
})

// 数据恢复配置
const dataRestore = ref({
  backupFile: ''
})

// 新增：数据恢复UI的状态管理
const backupFileOptions = ref([])
const backupFilesLoading = ref(false)
const backupInfo = ref(null)
const backupInfoLoading = ref(false)
const isTableBackup = computed(() => {
  const name = String(dataRestore.value.backupFile || '').toLowerCase()
  const byInfo = !!backupInfo.value && (
    String(backupInfo.value.backupContent || '').toUpperCase() === 'TABLE' ||
    String(backupInfo.value.type || '').toUpperCase() === 'TABLE'
  )
  return byInfo || name.includes('table')
})

// 提交状态
const creating = ref(false)
const restoring = ref(false)
const savingType = ref(false)
const savingParam = ref(false)

// 备份策略列表与状态
const strategyList = ref([])
const executingIds = ref([]) // 当前正在执行的策略ID集合
const lastBackupMap = ref({}) // { strategyId: 'YYYY-MM-DD HH:mm' }
const togglingIds = ref([]) // 正在切换启用/停用的策略ID集合
const deletingIds = ref([]) // 正在删除的策略ID集合

// 立即执行参数弹窗与表单
const executeDialogVisible = ref(false)
const executeSubmitting = ref(false)
const currentExecuteStrategyId = ref(null)
const executeForm = ref({
  ip: '127.0.0.1',
  databasePort: '5236',
  password: 'sYSDBA123',
  databaseName: 'SYSDBA',
  filePath: 'E:/shixiwork/地面站/backup',
  binPath: 'D://dameng/DM/bin'
})

// 将 UI 枚举映射为后端期望的字段值
const mapBackupType = val => {
  switch (val) {
    case 'incremental':
      return '增量备份'
    case 'differential':
      return '差异备份'
    default:
      return '全量备份'
  }
}
const mapBackupContent = val => (val === 'selected' ? 'TABLE' : 'DATABASE')
const mapBackupFrequency = val => {
  switch (val) {
    case 'daily':
      return 'DAILY'
    case 'weekly':
      return 'WEEKLY'
    default:
      return 'MONTHLY'
  }
}
const toLocalDateTimeString = (hhmm) => {
  // 将 HH:mm 转为本地时间字符串（不带 Z），格式：YYYY-MM-DDTHH:mm:00，日期取今日
  try {
    const [h, m] = String(hhmm || '00:00').split(':').map(v => parseInt(v, 10))
    const d = new Date()
    d.setHours(Number.isNaN(h) ? 0 : h)
    d.setMinutes(Number.isNaN(m) ? 0 : m)
    d.setSeconds(0)
    d.setMilliseconds(0)
    const z = (n) => (n < 10 ? `0${n}` : String(n))
    return `${d.getFullYear()}-${z(d.getMonth() + 1)}-${z(d.getDate())}T${z(d.getHours())}:${z(d.getMinutes())}:00`
  } catch (e) {
    const d = new Date()
    const z = (n) => (n < 10 ? `0${n}` : String(n))
    return `${d.getFullYear()}-${z(d.getMonth() + 1)}-${z(d.getDate())}T${z(d.getHours())}:${z(d.getMinutes())}:00`
  }
}
// 新增：规范化后端需要的 backupTime 字段为本地 ISO 字符串（中间带 T）
const normalizeBackupDateTime = (dt) => {
  if (!dt) return dt
  if (typeof dt === 'string') {
    let s = dt.trim()
    // 若是仅时间（HH:mm 或 HH:mm:ss），转换为今日的本地 ISO
    if (/^\d{2}:\d{2}(:\d{2})?$/.test(s)) {
      const hhmm = s.split(':').slice(0,2).join(':')
      return toLocalDateTimeString(hhmm)
    }
    // 将空格分隔的日期时间改为使用 T 分隔
    if (s.includes(' ')) s = s.replace(' ', 'T')
    // 若缺少秒，补全为 :00
    if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(s)) s = `${s}:00`
    return s
  }
  // 若传入 Date 或时间戳，转为本地 ISO（不带 Z）
  try {
    const d = new Date(dt)
    const z = (n) => (n < 10 ? `0${n}` : String(n))
    return `${d.getFullYear()}-${z(d.getMonth() + 1)}-${z(d.getDate())}T${z(d.getHours())}:${z(d.getMinutes())}:${z(d.getSeconds())}`
  } catch (_) {
    return dt
  }
}

// 展示用格式化
const formatStatus = s => {
  switch (s) {
    case 0:
      return '启用中'
    case 1:
      return '暂停'
    case 2:
      return '禁用'
    default:
      return '未知'
  }
}
const formatContent = c => (c === 'TABLE' ? '备份数据库表' : '备份数据库')
const pad = n => (n < 10 ? `0${n}` : String(n))
const formatFrequency = (freq, backupTime) => {
  // freq: DAILY/WEEKLY/MONTHLY；backupTime: ISO
  let timeStr = ''
  try {
    const d = new Date(backupTime)
    timeStr = `${pad(d.getHours())}:${pad(d.getMinutes())}`
  } catch (e) {}
  switch (freq) {
    case 'DAILY':
      return `每天 ${timeStr}`
    case 'WEEKLY':
      return `每周 ${timeStr}`
    case 'MONTHLY':
      return `每月 ${timeStr}`
    default:
      return `${freq || ''} ${timeStr}`.trim()
  }
}

// 获取策略列表
const fetchStrategyList = async () => {
  try {
    const res = await backupApi.getAllStrategies()
    const list = Array.isArray(res?.records) ? res.records : (Array.isArray(res) ? res : [])
    strategyList.value = list
    // 拉取每个策略的最后备份时间
    lastBackupMap.value = {}
    await Promise.all(
      list.map(async (item) => {
        try {
          const tasks = await backupApi.getStrategyTasks(item.id)
          const arr = Array.isArray(tasks?.records) ? tasks.records : (Array.isArray(tasks) ? tasks : [])
          const last = arr.sort((a, b) => new Date(b.createTime) - new Date(a.createTime))[0]
          if (last?.createTime) {
            const d = new Date(last.createTime)
            const s = `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
            lastBackupMap.value[item.id] = s
          }
        } catch (e) {
          // 忽略单个策略任务获取错误
        }
      })
    )
  } catch (e) {
    // 错误在拦截器提示
  }
}

// 执行策略备份
const executeNow = async (strategyId) => {
  if (!strategyId) return
  if (!executingIds.value.includes(strategyId)) executingIds.value.push(strategyId)
  try {
    await backupApi.executeStrategy(strategyId)
    message.success('备份任务已启动')
    // 执行后刷新“最后备份”显示
    await fetchStrategyList()
  } catch (e) {
    // 错误提示由拦截器统一处理
  } finally {
    executingIds.value = executingIds.value.filter(id => id !== strategyId)
  }
}

// 打开“立即执行”参数弹窗
const openExecuteDialog = (strategyId) => {
  currentExecuteStrategyId.value = strategyId
  // 每次打开重置为默认值，便于用户直接使用默认配置
  executeForm.value = {
    ip: '127.0.0.1',
    databasePort: '5236',
    password: 'sYSDBA123',
    databaseName: 'SYSDBA',
    filePath: 'E:/shixiwork/地面站/backup',
    binPath: 'D://dameng/DM/bin'
  }
  executeDialogVisible.value = true
}

// 确认执行：先创建任务，再触发执行
const confirmExecute = async () => {
  const strategyId = currentExecuteStrategyId.value
  if (!strategyId) {
    message.warning('未选择策略')
    return
  }
  executeSubmitting.value = true
  try {
    const payload = {
      strategyId,
      ip: String(executeForm.value.ip || '').trim() || '127.0.0.1',
      databasePort: String(executeForm.value.databasePort || '').trim() || '5236',
      password: String(executeForm.value.password || '').trim() || 'sYSDBA123',
      databaseName: String(executeForm.value.databaseName || '').trim() || 'SYSDBA',
      filePath: String(executeForm.value.filePath || '').trim() || 'E:/shixiwork/地面站/backup',
      binPath: String(executeForm.value.binPath || '').trim() || 'D://dameng/DM/bin'
    }
    await backupApi.createTaskWithStrategy(payload)
    await backupApi.executeStrategy(strategyId)
    message.success('已创建任务并启动备份')
    executeDialogVisible.value = false
    // 刷新卡片“最后备份”
    await fetchStrategyList()
  } catch (e) {
    // 错误提示由拦截器统一处理
  } finally {
    executeSubmitting.value = false
  }
}

// 启用/停用策略切换（根据当前状态构造严格参数并调用 PUT /backup-strategy）
const toggleStrategyStatus = async (item) => {
  if (!item?.id) return
  const nextStatus = item.status === 1 ? 0 : 1
  if (!togglingIds.value.includes(item.id)) togglingIds.value.push(item.id)
  try {
    // 按接口文档构造完整参数（与创建一致，需包含 id）
    let payload = {
      id: item.id,
      strategyName: item.strategyName,
      backupType: item.backupType,          // 全量备份/增量备份/差异备份（中文枚举）
      backupContent: item.backupContent,    // DATABASE/TABLE
      backupFrequency: item.backupFrequency,// DAILY/WEEKLY/MONTHLY
      backupTime: normalizeBackupDateTime(item.backupTime),          // ISO字符串，如 2025-10-16T02:00:00
      retention: item.retention,            // 30天/60天...（字符串）
      status: nextStatus                    // 0:启用, 1:暂停
    }

    // 如果列表项字段不完整，补充一次详情查询以满足后端校验
    if (!payload.backupType || !payload.backupContent || !payload.backupFrequency || !payload.backupTime || !payload.retention) {
      try {
        const detail = await backupApi.getStrategyDetail(item.id)
        payload = {
          id: item.id,
          strategyName: detail?.strategyName ?? item.strategyName,
          backupType: detail?.backupType ?? item.backupType,
          backupContent: detail?.backupContent ?? item.backupContent,
          backupFrequency: detail?.backupFrequency ?? item.backupFrequency,
          backupTime: normalizeBackupDateTime(detail?.backupTime ?? item.backupTime),
          retention: detail?.retention ?? item.retention,
          status: nextStatus
        }
      } catch (_) {
        // 若详情也失败，回退为现有字段（避免操作被完全阻塞）
      }
    }

    await backupApi.updateStrategy(payload)
    message.success(nextStatus === 1 ? '策略已停用' : '策略已启用')
    await fetchStrategyList()
  } catch (e) {
    // 错误由拦截器提示
  } finally {
    togglingIds.value = togglingIds.value.filter(id => id !== item.id)
  }
}

// 删除策略（需要确认）
const deleteStrategy = async (item) => {
  if (!item?.id) return
  if (!deletingIds.value.includes(item.id)) deletingIds.value.push(item.id)
  try {
    await backupApi.deleteStrategy(item.id)
    message.success('策略已删除')
    await fetchStrategyList()
  } catch (e) {
    // 错误由拦截器提示
  } finally {
    deletingIds.value = deletingIds.value.filter(id => id !== item.id)
  }
}

// 提交：存储类型配置（POST /storage-type-config）
const submitStorageTypeConfig = async () => {
  // 兜底默认值，保障请求发出
  if (!storageConfig.value.structuredDb) storageConfig.value.structuredDb = 'mysql'
  // 表单“数据库连接地址”现对应接口字段 dbPort
  if (!storageConfig.value.dbAddress) storageConfig.value.dbAddress = '3306'
  if (!storageConfig.value.dbName) storageConfig.value.dbName = 'default_db'
  if (!storageConfig.value.unstructuredDb) storageConfig.value.unstructuredDb = 'hdfs'
  if (!storageConfig.value.unstructuredDbType) storageConfig.value.unstructuredDbType = 'mongodb'

  // 按新映射：
  // 数据库连接地址 => dbPort（端口号）
  // 存储路径       => dbHost（主机地址）
  const portStr = String(storageConfig.value.dbAddress || '').trim()
  let port = parseInt(portStr, 10)
  if (Number.isNaN(port)) {
    // 根据结构化数据库类型设定默认端口
    switch (storageConfig.value.structuredDb) {
      case 'postgresql':
        port = 5432
        break
      case 'oracle':
        port = 1521
        break
      default:
        port = 3306
    }
  }

  let host = String(storageConfig.value.storagePath || '').trim() || 'localhost'

  const payload = {
    structDataStore: storageConfig.value.structuredDb, // mysql/postgresql/oracle
    dbHost: host,
    dbPort: port,
    dbName: storageConfig.value.dbName,
    nonStructDataStore: storageConfig.value.unstructuredDb, // hdfs/ceph/glusterfs
    semiStructDataStore: storageConfig.value.unstructuredDbType // mongodb/cassandra/redis
  }

  savingType.value = true
  try {
    await storageApi.addStorageTypeConfig(payload)
    message.success('存储类型配置已保存')
  } catch (e) {
    // 错误提示在拦截器中处理
  } finally {
    savingType.value = false
  }
}

// 提交：存储参数配置（POST /storage-param-config）
const submitStorageParamConfig = async () => {
  // 兜底默认值
  const maxConnsStr = String(poolStatus.value.maxConnections ?? '').trim()
  const maxConns = Number(maxConnsStr)
  const payload = {
    createBy: 'frontend',
    isDeleted: 0,
    createTime: new Date().toISOString(),
    updateTime: new Date().toISOString(),
    logRetentionPeriod: String(poolStatus.value.logRetention || '60'),
    maxConnections: Number.isNaN(maxConns) ? 100 : maxConns,
    transactionIsolation: poolStatus.value.isolationLevel || 'READ COMMITTED'
  }

  savingParam.value = true
  try {
    await storageApi.addStorageParamConfig(payload)
    message.success('存储参数配置已保存')
  } catch (e) {
    // 错误提示在拦截器中处理
  } finally {
    savingParam.value = false
  }
}

// 新建备份策略提交（严格按接口文档字段）
const submitBackupStrategy = async () => {
  // 不再阻塞提交，若值缺失则使用兜底默认值，保障联调请求发出
  const inputName = String(backupStrategy.value.strategyName || '').trim()
  if (!inputName) {
    backupStrategy.value.strategyName = `策略-${Date.now()}`
  } else {
    backupStrategy.value.strategyName = inputName
  }
  if (!backupStrategy.value.backupContent) {
    backupStrategy.value.backupContent = 'all'
  }
  creating.value = true
  try {
    const payload = {
      strategyName: backupStrategy.value.strategyName,
      backupType: mapBackupType(backupStrategy.value.backupType),
      backupContent: mapBackupContent(backupStrategy.value.backupContent), // DATABASE/TABLE
      backupFrequency: mapBackupFrequency(backupStrategy.value.backupFrequency), // DAILY/WEEKLY/MONTHLY
      backupTime: toLocalDateTimeString(backupStrategy.value.backupTime),
      retention: `${backupStrategy.value.retentionTime || '60'}天`,
      status: 0
    }

    await backupApi.createStrategy(payload)
    message.success('备份策略创建成功')
    // 创建成功后刷新策略列表
    await fetchStrategyList()
  } catch (e) {
    // 错误提示在请求拦截器中已处理，这里仅确保状态复位
  } finally {
    creating.value = false
  }
}

// 数据恢复提交（集成后台恢复接口）
const fetchBackupFiles = async () => {
  backupFilesLoading.value = true
  try {
    const list = await backupApi.getBackupFiles()
    backupFileOptions.value = Array.isArray(list) ? list : []
  } catch (e) {
    // 错误提示交由拦截器
  } finally {
    backupFilesLoading.value = false
  }
}

// 选择备份文件后，获取该文件详情
const handleBackupFileChange = async (val) => {
  dataRestore.value.backupFile = val
  backupInfo.value = null
  if (!val) return
  await fetchBackupFileInfo(val)
}

const fetchBackupFileInfo = async (filename) => {
  backupInfoLoading.value = true
  try {
    const info = await backupApi.getBackupFileInfo(filename)
    backupInfo.value = info || null
  } catch (e) {
    // 错误提示交由拦截器
  } finally {
    backupInfoLoading.value = false
  }
}

// 数据恢复提交（集成后台恢复接口）
const startRestore = async () => {
  const filename = dataRestore.value.backupFile
  if (!filename) {
    message.warning('请先选择备份文件')
    return
  }
  // 确保已获取详情（恢复参数来自详情）
  if (!backupInfo.value || backupInfo.value?.filename !== filename) {
    await fetchBackupFileInfo(filename)
    if (!backupInfo.value) {
      message.error('未能获取备份文件详情，无法恢复')
      return
    }
  }

  const info = backupInfo.value
  const payload = {
    ip: info.ip,
    databasePort: info.databasePort,
    password: info.password,
    databaseName: info.databaseName,
    filePath: info.filePath,
    binPath: info.binPath,
    filename: info.filename,
    ...(info.tables ? { tables: info.tables } : {})
  }

  restoring.value = true
  try {
    if (isTableBackup.value) {
      await backupApi.restoreTables(payload)
      message.success('表级恢复请求已提交')
    } else {
      await backupApi.restoreDatabase(payload)
      message.success('库级恢复请求已提交')
    }
  } catch (e) {
    // 错误提示交由拦截器统一处理
  } finally {
    restoring.value = false
  }
}

// 初始化备份页：统一拉取策略列表与备份文件
const initBackupTab = () => {
  fetchStrategyList()
  fetchBackupFiles()
}

// 在进入“备份与恢复”页时拉取策略列表
onMounted(() => {
  if (activeTab.value === 'backup') {
    initBackupTab()
  }
})
watch(activeTab, (val) => {
  if (val === 'backup') {
    initBackupTab()
  }
})
// 防抖（节流）处理：开始恢复按钮，避免用户快速重复点击
const handleStartRestoreClick = (() => {
  let last = 0;
  return async () => {
    const now = Date.now();
    if (now - last < 1200) {
      message.warning('请勿频繁点击');
      return;
    }
    last = now;
    await startRestore();
  };
})();
</script>

<style scoped>
.section-title{
  opacity: 1;
  color: #FFFFFF;
  font-family: Source Han Sans;
  font-weight: bold;
  font-size: 18px;
  line-height: 40px;
  letter-spacing: 0px;
  text-align: left;
  margin-left:0%
}
.storage-config-container {
  display: flex;
  height: calc(100vh - 64px);
  background: #0a1628;
}

.sidebar {
  width: 240px;
  background: #1f2937;
  border-right: 1px solid #374151;
  flex-shrink: 0;
}

.sidebar-menu {
  padding: 0;
}

.menu-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 20px;
  color: #9ca3af;
  cursor: pointer;
  transition: all 0.3s;
  border-bottom: 1px solid #374151;
  font-size: 14px;
  font-weight: 500;
}

.menu-item:hover {
  background: #374151;
  color: #f3f4f6;
}

.menu-item.active {
  background: #1e40af;
  color: #ffffff;
}

.menu-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.main-content {
  flex: 1;
  padding: 24px;
  overflow-y: auto;
  background: #0a1628;
}

.config-content {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.config-section {
  background: #1f2937;
  border-radius: 8px;
  border: 1px solid #374151;
  overflow: hidden;
}

.section-header {
  padding: 20px 24px;
  border-bottom: 1px solid #374151;
  background: #111827;
}

.section-header h3 {
  color: #f3f4f6;
  margin: 0;
  font-size: 16px;
  font-weight: 600;
}

.form-container {
  padding: 24px;
}

.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px 32px;
  margin-bottom: 32px;
}

.form-grid-two-column {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px;
  margin-bottom: 32px;
}

.form-column {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.form-row {
  display: flex;
  align-items: center;
  gap: 16px;
}

/* 设为整行显示（跨两列） */
.form-row.full-width {
  grid-column: 1 / -1;
}

.form-row label {
  color: #e5e7eb;
  min-width: 140px;
  font-size: 14px;
  font-weight: 600;
  text-align: right;
}

.form-row .ant-input,
.form-row .ant-select {
  flex: 1;
}

.form-actions {
  display: flex;
  justify-content: flex-start;
  padding-left: 156px;
}

.form-actions .ant-btn {
  min-width: 100px;
  height: 36px;
  font-weight: 500;
}

/* 备份卡片样式 */
.backup-cards {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 16px;
  padding: 16px 24px;
}

.backup-card {
  background: #111827;
  border: 1px solid #374151;
  border-radius: 8px;
  padding: 16px;
  transition: all 0.3s;
}

.backup-card:hover {
  border-color: #3b82f6;
  box-shadow: 0 4px 12px rgba(59, 130, 246, 0.15);
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
}

.card-title {
  color: #f3f4f6;
  font-size: 14px;
  font-weight: 600;
}

.card-status {
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 500;
}

.card-status.active {
  background: #10b981;
  color: #ffffff;
}

.card-status.inactive {
  background: #ef4444;
  color: #ffffff;
}

.card-content {
  margin-bottom: 16px;
}

.card-info {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.info-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.info-label {
  color: #9ca3af;
  font-size: 13px;
}

.info-value {
  color: #d1d5db;
  font-size: 13px;
  font-weight: 500;
}

.card-actions {
  display: flex;
  justify-content: center;
}

.card-actions .ant-btn {
  min-width: 80px;
}

/* 响应式设计 */
@media (max-width: 1600px) {
  .backup-cards {
    grid-template-columns: repeat(4, 1fr);
  }
}

@media (max-width: 1200px) {
  .form-grid {
    grid-template-columns: 1fr;
  }
  
  .backup-cards {
    grid-template-columns: repeat(2, 1fr);
  }
  
  .sidebar {
    width: 200px;
  }
}

@media (max-width: 768px) {
  .storage-config-container {
    flex-direction: column;
  }
  
  .sidebar {
    width: 100%;
    height: auto;
  }
  
  .sidebar-menu {
    display: flex;
  }
  
  .menu-item {
    flex: 1;
    justify-content: center;
    border-bottom: none;
    border-right: 1px solid #374151;
  }
  
  .menu-item:last-child {
    border-right: none;
  }
}

/* Ant Design Vue 组件样式覆盖 */
:deep(.ant-input) {
  background: #111827;
  border-color: #374151;
  color: #f3f4f6;
}

/* 调整 placeholder 提示字颜色为浅灰，适配暗色主题 */
:deep(.ant-input::placeholder) {
  color: #9ca3af;
}

:deep(.ant-input:hover) {
  border-color: #3b82f6;
}

:deep(.ant-input:focus) {
  border-color: #3b82f6;
  box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
}

:deep(.ant-select) {
  color: #f3f4f6;
}

:deep(.ant-select .ant-select-selector) {
  background: #111827;
  border-color: #374151;
  color: #f3f4f6;
}

/* Ant Select 的 placeholder 颜色（兼容不同版本的类名） */
:deep(.ant-select .ant-select-selection-placeholder),
:deep(.ant-select .ant-select-selection__placeholder) {
  color: #9ca3af;
}

:deep(.ant-select:hover .ant-select-selector) {
  border-color: #3b82f6;
}

:deep(.ant-select-focused .ant-select-selector) {
  border-color: #3b82f6;
  box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
}

:deep(.ant-select-arrow) {
  color: #9ca3af;
}

:deep(.ant-btn-primary) {
  background: #3b82f6;
  border-color: #3b82f6;
}

:deep(.ant-btn-primary:hover) {
  background: #2563eb;
  border-color: #2563eb;
}

.execute-modal .tip-row {
  margin-top: 8px;
  color: #9ca3af;
  font-size: 12px;
}
</style>

<style>
/* Execute Params Modal - Light theme, global scope to override teleport */
.light-modal .ant-modal-content {
  background: #ffffff;
  border: 1px solid #e5e7eb;
}
.light-modal .ant-modal-header {
  background: #ffffff;
  border-bottom: 1px solid #e5e7eb;
}
.light-modal .ant-modal-footer {
  background: #ffffff;
  border-top: 1px solid #e5e7eb;
}
.light-modal .ant-modal-title {
  color: #111827;
}
.light-modal .ant-modal-close-x,
.light-modal .ant-modal-close {
  color: #6b7280;
}

/* Body text and labels */
.light-modal .ant-modal-body {
  color: #111827;
}
.light-modal .ant-modal-body label {
  color: #111827;
  font-weight: 600;
}

/* Inputs and password fields - white background, black text */
.light-modal .ant-input,
.light-modal .ant-input-password,
.light-modal .ant-input-affix-wrapper {
  background: #ffffff;
  border-color: #d1d5db;
  color: #111827;
}
.light-modal .ant-input::placeholder,
.light-modal .ant-input-password input::placeholder,
.light-modal .ant-input-affix-wrapper input::placeholder {
  color: #6b7280;
}
.light-modal .ant-input:hover,
.light-modal .ant-input-password:hover,
.light-modal .ant-input-affix-wrapper:hover {
  border-color: #3b82f6;
}
.light-modal .ant-input:focus,
.light-modal .ant-input-affix-wrapper-focused {
  border-color: #3b82f6;
  box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.15);
}
.light-modal .ant-input-affix-wrapper .ant-input-suffix .anticon {
  color: #6b7280;
}

/* Select fields - white background, black text */
.light-modal .ant-select {
  color: #111827;
}
.light-modal .ant-select .ant-select-selector {
  background: #ffffff;
  border-color: #d1d5db;
  color: #111827;
}
.light-modal .ant-select .ant-select-selection-placeholder,
.light-modal .ant-select .ant-select-selection__placeholder {
  color: #6b7280;
}
.light-modal .ant-select:hover .ant-select-selector {
  border-color: #3b82f6;
}
.light-modal .ant-select-focused .ant-select-selector {
  border-color: #3b82f6;
  box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.15);
}

/* Ensure two-column grid layout inside the execute modal */
.light-modal .execute-modal .form-grid {
  display: grid;
  grid-template-columns: repeat(1, minmax(0, 1fr));
  column-gap: 32px;
  row-gap: 20px;
  align-items: center;
}
.light-modal .execute-modal .form-row {
  width: 100%;
}
</style>